package gateway

import (
	"errors"
	"gitee.com/sansaniot/ssiot-gw-lib/device"
	ssiot2 "gitee.com/sansaniot/ssiot-gw-lib/ssiot"
	msgbus2 "gitee.com/sansaniot/ssiot-gw-lib/ssiot/msgbus"
	"github.com/rs/zerolog/log"
)

var (
	MOD_NAME_SUBDEVICE = "subdevice"
	MOD_NAME_GATEWAY   = "gateway"
	HAS_CONFIG         = false
)

var Config struct {
	ModSubDevice interface{} `json:"subdevice" yaml:"subdevice"`
	ModGateway   interface{} `json:"gateway" yaml:"gateway"`
}

func RegisterSubDeviceConfig(c interface{}) {
	if c != nil {
		Config.ModSubDevice = c
		HAS_CONFIG = true
	}
}

func RegisterGatewayConfig(c interface{}) {
	if c != nil {
		Config.ModGateway = c
		HAS_CONFIG = true
	}
}

var sensorSetHandler func(sid uint64, devSn string, setdata interface{}) error
var configSetHandler func(sid uint64, devSn string, setconf interface{}) error

func RegisterSensorSetHandler(f func(sid uint64, devSn string, setdata interface{}) error) {
	sensorSetHandler = f
}

func RegisterConfigSetHandler(f func(sid uint64, devSn string, setconf interface{}) error) {
	configSetHandler = f
}

func SaveGatewayConfig(c interface{}) error {
	if c == nil {
		return errors.New("config object is nil")
	}

	Config.ModGateway = c
	ssiot2.SaveModSettingsToYamlAndPlat(MOD_NAME_GATEWAY, c)
	return nil
}

func Init() {
	if HAS_CONFIG == false {
		log.Warn().Msgf("gateway has no config")
	} else if Config.ModGateway != nil {
		// 将配置文件的配置写入结构体， 注意：结构体是interface类型时，用&Config.ModGateway传入，动态类型会出现*interface{}，会出错
		ssiot2.LoadModSettings(MOD_NAME_GATEWAY, Config.ModGateway)
		// 从平台获取配置，并和本地配置合并保存
		ssiot2.SyncModSettings(MOD_NAME_GATEWAY, Config.ModGateway)

	} else if Config.ModSubDevice != nil {
		ssiot2.LoadModSettings(MOD_NAME_SUBDEVICE, Config.ModSubDevice)
		ssiot2.SyncModSettings(MOD_NAME_SUBDEVICE, Config.ModSubDevice)
	}

	// 注册handler
	msgbus2.RegisteDispatch(DispatchHandler)

	if sensorSetHandler != nil {
		device.RegisterSensorSetHandler(sensorSetHandler)
	}

	if configSetHandler != nil {
		device.RegisterConfigSetHandler(configSetHandler)
	}
}

func Fini() {
}

func DispatchHandler(biz string, iot *msgbus2.MsgIoT) {
	// 发给设备
	if iot.To != ssiot2.Sn() {
		if biz == msgbus2.CONFIG_SET {
			device.ConfigSet(iot.Sid, iot.To, iot.Data)
		}

		if biz == msgbus2.SENSOR_SET {
			device.SensorSet(iot.Sid, iot.To, iot.Data)
		}

		// 发给网关
	} else if HAS_CONFIG {
		if biz == msgbus2.CONFIG_SET {
			configSet(iot)
		}

		if biz == msgbus2.CONFIG_GET {
			configGet(iot)
		}
	}
}

func configSet(iot *msgbus2.MsgIoT) {
	data, ok := iot.Data.(map[string]interface{})
	if !ok {
		ackConfigSet(iot.Sid, ssiot2.Sn(), 400, "invalid message")
		return
	}

	for k, _ := range data {
		if (k != MOD_NAME_SUBDEVICE && k != ssiot2.MOD_NAME && k != MOD_NAME_GATEWAY) || len(data[k].(map[string]interface{})) == 0 {
			delete(data, k)
		}
	}

	iot.Data = data
	ssiot2.LoadSettingsFromMessage(iot)
	ssiot2.SaveSettingsToYaml("")
	ackConfigSet(iot.Sid, ssiot2.Sn(), 200, "success")
}

func ackConfigSet(sid uint64, devSn string, code int, msg string) {
	iot := msgbus2.NewMsgIoT(msgbus2.ACK_CONFIG_SET, "$", devSn, nil)
	iot.Sid = sid
	iot.Code = code
	iot.Msg = msg
	iot.Publish()
}

func configGet(iot *msgbus2.MsgIoT) {
	data, ok := iot.Data.(map[string]interface{})
	if !ok {
		ackConfigSet(iot.Sid, ssiot2.Sn(), 400, "invalid message")
		return
	}

	iot.Data = data
	settings := ssiot2.LoadSettingsFromYaml("")

	iotAck := &msgbus2.MsgIoT{
		Sid:  iot.Sid,
		Code: 200,
		Msg:  "success",
		Biz:  msgbus2.ACK_CONFIG_GET,
		Data: settings,
	}

	iotAck.Publish()
}
